package work.mediway.mdm.biz.job;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxl.job.core.handler.annotation.XxlJob;

import org.springframework.stereotype.Component;

import java.util.List;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import work.mediway.mdm.biz.entity.patient.PaPatient;
import work.mediway.mdm.biz.entity.patient.PaSuspectPatient;
import work.mediway.mdm.biz.service.patient.PaPatientService;
import work.mediway.mdm.biz.service.patient.PaSuspectPatientService;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2020/8/5
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PatientSuspectJob {

    private static final Integer DEFAULT_SIZE = 1000;

    private final PaPatientService paPatientService;
    private final PaSuspectPatientService paSuspectPatientService;

    /**
     * Scheduled(cron = "0 0 1 * * ? ")
     * 根据传入时间统计相似患者，默认统计当天
     */
    @XxlJob("patientSuspectHandler")
    public void patientSuspectHandler(String startDate, String endDate) {
        log.info("========================== 定时任务统计相似患者 开始 ==========================");
        if (StrUtil.isBlank(startDate)) {
            startDate = DateUtil.today();
        }
        if (StrUtil.isBlank(endDate)) {
            endDate = DateUtil.today();
        }
        LambdaQueryWrapper<PaPatient> wrapper = Wrappers.lambdaQuery(PaPatient.class)
                .ge(PaPatient::getUpdateDate, startDate)
                .le(PaPatient::getUpdateDate, endDate);

        long majorCount = this.paPatientService.count(wrapper);

        if (majorCount != 0) {
            if (majorCount / DEFAULT_SIZE == 0) {
                // 获取一部分主患者
                batchMajorPatient(wrapper, 0);
            } else {
                if (majorCount % DEFAULT_SIZE == 0) {
                    for (int i = 0; i < (majorCount / DEFAULT_SIZE); i++) {
                        batchMajorPatient(wrapper, i);
                    }
                } else {
                    for (int i = 0; i < (majorCount / DEFAULT_SIZE) + 1; i++) {
                        batchMajorPatient(wrapper, i);
                    }
                }
            }
        }
        log.info("========================== 定时任务统计相似患者 完成 ==========================");
    }

    /**
     * 分批获取主患者
     *
     * @param wrapper 获取主患者条件
     * @param page    分页
     */
    private void batchMajorPatient(LambdaQueryWrapper<PaPatient> wrapper, int page) {
        Page<PaPatient> patientPage = new Page<>(page, DEFAULT_SIZE);
        Page<PaPatient> majorPatients = this.paPatientService.page(patientPage, wrapper);
        for (PaPatient majorPatient : majorPatients.getRecords()) {
            // 查询另外的对比患者，然后计算
            LambdaQueryWrapper<PaPatient> neWrapper = Wrappers.lambdaQuery(PaPatient.class).ne(PaPatient::getPatPatientId, majorPatient.getPatPatientId());
            long suspectCount = this.paPatientService.count(neWrapper);

            if (suspectCount / DEFAULT_SIZE == 0) {
                batchCompute(majorPatient, neWrapper, 0);
            } else {
                if (suspectCount % DEFAULT_SIZE == 0) {
                    for (int i = 0; i < (suspectCount / DEFAULT_SIZE); i++) {
                        batchCompute(majorPatient, neWrapper, i);
                    }
                } else {
                    for (int i = 0; i < (suspectCount / DEFAULT_SIZE) + 1; i++) {
                        batchCompute(majorPatient, neWrapper, i);
                    }
                }
            }
        }
    }

    /**
     * 分批计算相似度
     *
     * @param majorPatient 主患者
     * @param neWrapper    其他患者查询条件
     * @param page         分页
     */
    private void batchCompute(PaPatient majorPatient, LambdaQueryWrapper<PaPatient> neWrapper, int page) {
        Page<PaPatient> patientPage = new Page<>(page, DEFAULT_SIZE);
        Page<PaPatient> list = this.paPatientService.page(patientPage, neWrapper);
        for (PaPatient patient : list.getRecords()) {
            List<PaSuspectPatient> suspectPatients = this.paSuspectPatientService.computeSuspect(majorPatient.getPatPatientId(), patient.getPatPatientId());
            this.paSuspectPatientService.saveSuspect(suspectPatients);
        }
    }

}